//-------------------------------------------------------------------------------------------------
//  sphere.hpp - Definition of sphere class for physics operations
//  (c) 2009 Simon Miessler
//-------------------------------------------------------------------------------------------------

#pragma once

#include "math_exports.hpp"
#include "geometry_fwd.hpp"
#include "vector3.hpp"
#include "intersectable.hpp"
#include "raycastable.hpp"




namespace math
{
	/**
	 * Sphere represents a sphere in 3d space (that was tough to explain).
	 */
	template <typename T>
	class sphere
		: public intersectable< sphere<T> >
		, public raycastable< sphere<T>, T >
	{
	public:

		/// The used floating-point type
		typedef T   float_t;

	public:

		/// Position of the sphere
		vector3<T>   position;

		/// Radius of the sphere
		T            radius;

	public:

		/**
		 * Create a bounding sphere.
		 * It is located at (0,0,0) with a radius of 1.
		 */
		sphere()
			: position(0, 0, 0)
			, radius(1)
		{}

		/**
		 * Create a bounding sphere at the specified position with the
		 * specified radius.
		 *
		 * @param position   the position of the sphere in world space
		 * @param radius     the radius of the sphere
		 */
		sphere(const vector3<T>& position, T radius)
			: position(position)
			, radius(radius)
		{
			assert(radius >= 0);
		}
	};
	///////////////////////////////////////////////////////////////////////////////////////////////




	/**
	 * Transform a Sphere by a 4x4 matrix.
	 *
	 * @return   the transformed sphere
	 */
	template <typename T>
	sphere<T> transform(const matrix4x4<T>& lhs, const sphere<T>& rhs)
	{
		// TODO: Test against scaling matrix
		return sphere<T>(transform(lhs, rhs.position), rhs.radius);
	}
	///////////////////////////////////////////////////////////////////////////////////////////////




	/**
	 * In order to compile a binary that actually contains the code for our Spheres,
	 * we have to explicitly instantiate the template Spheres and export those:
	 */
	template struct MATH_API intersectable< sphere<float> >;
	template struct MATH_API intersectable< sphere<double> >;
	template struct MATH_API raycastable< sphere<float>, float>;
	template struct MATH_API raycastable< sphere<double>, double>;
	template class MATH_API sphere<float>;
	template class MATH_API sphere<double>;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
